﻿using MasterDetailTemplate.Models;
using SQLite;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using DeferredEvents;

namespace MasterDetailTemplate.Services {
    /// <summary>
    /// 事件存储。
    /// By FJH
    /// </summary>
    public class EventStorage : IEventStorage {
        /// <summary>
        /// 数据库名。
        /// </summary>
        private const string DbName = "date.db";

        /// <summary>
        /// 事件存储已更新的事件
        /// </summary>
        public event EventHandler<EventStorageUpdatedEventArgs> Updated;

        /// <summary>
        /// 事件存储。
        /// </summary>
        /// <param name="preferenceStorage">偏好存储。</param>
        public EventStorage(IPreferenceStorage preferenceStorage) {
            _preferenceStorage = preferenceStorage;
        }

        /// <summary>
        /// 偏好存储。
        /// </summary>
        private IPreferenceStorage _preferenceStorage;

        /// <summary>
        /// 事件数据库路径。
        /// </summary>
        public static readonly string EventDbPath =
            Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder
                    .LocalApplicationData), DbName);

        /// <summary>
        /// 数据库版本。
        /// </summary>
        public const int Version = 3;

        /// <summary>
        /// 数据库版本键。
        /// </summary>
        public const string VersionKey =
            nameof(EventStorage) + "." + nameof(Version);

        /// <summary>
        /// 数据库连接影子变量。
        /// </summary>
        private SQLiteAsyncConnection _connection;

        /// <summary>
        /// 数据库连接。
        /// </summary>
        private SQLiteAsyncConnection Connection =>
            _connection ??
            (_connection = new SQLiteAsyncConnection(EventDbPath));

        /// <summary>
        /// 初始化事件存储。
        /// </summary>
        public async Task InitializeAsync() {
            using (var dbFileStream =
                new FileStream(EventDbPath, FileMode.Create))
            using (var dbAssertStream = Assembly.GetExecutingAssembly()
                .GetManifestResourceStream(DbName)) {
                await dbAssertStream.CopyToAsync(dbFileStream);
            }

            _preferenceStorage.Set(VersionKey, Version);
        }

        /// <summary>
        /// 事件存储是否已经初始化。
        /// </summary>
        public bool Initialized() =>
            _preferenceStorage.Get(VersionKey, -1) == Version;

        /// <summary>
        /// 新建或更新一个事件。
        /// </summary>
        /// <param name="events"></param>
        public async Task SaveEventAsync(Event events) {
            events.DateStamp = DateTime.Now.Ticks;
            await Connection.InsertOrReplaceAsync(events);
            await Updated.InvokeAsync(this,
                new EventStorageUpdatedEventArgs(events));
        }

        /// <summary>
        /// 删除一个事件。
        /// </summary>
        /// <param name="events"></param>
        public async Task<int> DeleteEventAsync(Event events) {
            return await Connection.DeleteAsync(events);
            /*OnCountersChanged();*/
        }

        public async Task DeleteAllEvent() =>
            await Connection.DeleteAllAsync<Event>();

        /// <summary>
        /// 获取一个事件。
        /// </summary>
        /// <param name="id">事件id。</param>
        public async Task<Event> GetEventAsync(long id) =>
            await Connection.Table<Event>().Where(e => e.Id == id)
                .FirstOrDefaultAsync();

        /// <summary>
        /// 获得所有事件。
        /// </summary>
        public async Task<List<Event>> GetAllEventsAsync() =>
            await Connection.Table<Event>().ToListAsync();

        /// <summary>
        /// 获取满足给定条件的事件集合。
        /// </summary>
        /// <param name="where">Where条件。</param>
        /// <param name="skip">跳过数量。</param>
        /// <param name="take">获取数量。</param>
        public async Task<List<Event>> GetEventsAsync(
            Expression<Func<Event, bool>> @where, int skip, int take) =>
            await Connection.Table<Event>().Where(@where).Skip(skip).Take(take)
                .ToListAsync();

        /// <summary>
        /// 添加一个事件。
        /// </summary>
        /// <param name="events">事件。</param>
        /// <returns></returns>
        public async Task InsertEventAsync(Event events) =>
            await Connection.InsertAsync(events);


        /// <summary>
        /// 
        /// </summary>
        public event EventHandler CountersChanged;

        private void OnCountersChanged() {
            CountersChanged?.Invoke(this, new EventArgs());
        }

        /// <summary>
        /// 获得所有纪念日
        /// </summary>
        /// <returns></returns>
        public async Task<List<Event>> GetMemoryDaysAsync() =>
            await Connection.Table<Event>().Where(e => e.Attribute == 1)
                .ToListAsync();

        /// <summary>
        /// 获得所有倒数日
        /// </summary>
        /// <returns></returns>
        public async Task<List<Event>> GetCountdownDaysAsync() =>
            await Connection.Table<Event>().Where(e => e.Attribute == 2)
                .ToListAsync();

        /// <summary>
        /// 关闭事件数据库。
        /// </summary>
        /// <returns></returns>
        public async Task CloseAsync() => await Connection.CloseAsync();
    }
}